package com.practice.zuocy.base.class08;

/*
 * 二叉树的递归套路概述：
 * （1）可以解决面试中绝大多数的二叉树问题，尤其是树形dp问题
 * （2）本质是利用递归遍历二叉树的便利性
 */

/*
 * 二叉树的递归套路：
 * （1）假设以x节点为头，假设可以向x左树和x右树要任何信息
 * （2）在上一步的假设下，讨论以x为头节点的树，得到答案的可能性（最重要）
 * （3）列出所有可能性后，确定到底需要向左树和右树要什么样的信息
 * （4）把左树信息和右树信息求全集，就是任何一颗子树都需要返回的信息S
 * （5）递归函数都返回S，每一棵子树都这么要求
 * （6）写代码，在代码中考虑如何把左树的信息和右树的信息整合出整棵树的信息
 */

/**
 * 【题目】：
 * 给定一颗二叉树的头节点head，返回这棵二叉树是不是平衡二叉树
 */
public class Code01_IsBalanced {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	public static boolean isBalanced1(Node head) {
		boolean[] ans = new boolean[1];
		ans[0] = true;
		process1(head, ans);
		return ans[0];
	}

	public static int process1(Node head, boolean[] ans) {
		if (!ans[0] || head == null) {
			return -1;
		}
		int leftHeight = process1(head.left, ans);
		int rightHeight = process1(head.right, ans);
		if (Math.abs(leftHeight - rightHeight) > 1) {
			ans[0] = false;
		}
		return Math.max(leftHeight, rightHeight) + 1;
	}

	public static boolean isBalanced2(Node head) {
		return process2(head).isBalaced;
	}

	// 左、右要求一样，Info 信息返回的结构体
	public static class Info {
		// 该子树是否是平衡的
		public boolean isBalaced;
		// 该子树的高度
		public int height;

		public Info(boolean b, int h) {
			isBalaced = b;
			height = h;
		}
	}

	public static Info process2(Node X) {
		if (X == null) {
			return new Info(true, 0);
		}
		// 左树信息
		Info leftInfo = process2(X.left);
		// 右树信息
		Info rightInfo = process2(X.right);
		// 当前子树的高度为：左树高度和右树高度的最大值+1
		int height = Math.max(leftInfo.height, rightInfo.height) + 1;
		boolean isBalanced = true;
		if (!leftInfo.isBalaced
				|| !rightInfo.isBalaced
				|| Math.abs(leftInfo.height - rightInfo.height) > 1) {
			// （1）左树不平衡
			// （2）右树不平衡
			// （3）左右两树的高度差 > 1
			// 说明当前树不平衡
			isBalanced = false;
		}
		// 当前树构建信息返回
		return new Info(isBalanced, height);
	}

	// for test
	public static Node generateRandomBST(int maxLevel, int maxValue) {
		return generate(1, maxLevel, maxValue);
	}

	// for test
	public static Node generate(int level, int maxLevel, int maxValue) {
		if (level > maxLevel || Math.random() < 0.5) {
			return null;
		}
		Node head = new Node((int) (Math.random() * maxValue));
		head.left = generate(level + 1, maxLevel, maxValue);
		head.right = generate(level + 1, maxLevel, maxValue);
		return head;
	}

	public static void main(String[] args) {
		int maxLevel = 5;
		int maxValue = 100;
		int testTimes = 1000000;
		for (int i = 0; i < testTimes; i++) {
			Node head = generateRandomBST(maxLevel, maxValue);
			if (isBalanced1(head) != isBalanced2(head)) {
				System.out.println("Oops!");
			}
		}
		System.out.println("finish!");
	}

}
